//
// Created by zhuanzhu on 25-6-30.
//
#include <stdio.h>
#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib")  // 链接 Winsock 2 库

#define ECHO_DEF_PORT 7             // 默认端口号（标准回显服务端口）
#define ECHO_BUF_SIZE 1024          // 接收缓冲区大小

int main(int argc, char *argv[])
{
    WSADATA wsa_data;               // 存储 Winsock 初始化信息
    SOCKET echo_soc =0, acpt_soc =0; // 监听套接字和接受连接的套接字
    struct sockaddr_in serv_addr, clnt_addr; // 服务器和客户端地址结构
    unsigned short port = ECHO_DEF_PORT;     // 默认端口
    int result = 0;                     // 函数返回值
    int addr_len = sizeof(struct sockaddr_in); // 地址结构长度
    char recv_buf[ECHO_BUF_SIZE];       // 接收数据缓冲区

    // 若命令行提供参数，则使用指定端口
    if(argc == 2)
        port = atoi(argv[1]);

    // 初始化 Winsock 库，请求 2.2 版本
    WSAStartup(MAKEWORD(2,2), &wsa_data);

    // 创建 TCP 套接字
    echo_soc = socket(AF_INET, SOCK_STREAM, 0);

    // 配置服务器地址结构
    serv_addr.sin_family = AF_INET;             // IPv4 协议族
    serv_addr.sin_port = htons(port);           // 转换为网络字节序
    serv_addr.sin_addr.s_addr = INADDR_ANY;     // 监听所有可用接口

    // 将套接字绑定到指定地址和端口
    result = bind(echo_soc, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
    if (result == SOCKET_ERROR)
    {
        printf("[Echo server] bind error:%d\n", WSAGetLastError());
        closesocket(echo_soc);
        return -1;
    }

    // 开始监听连接请求，最大队列长度为 SOMAXCONN
    listen(echo_soc, SOMAXCONN);
    printf("[Echo Server] is running... ...\n");

    // 服务器主循环，持续接受客户端连接
    while(1)
    {
        // 接受客户端连接，返回新的套接字用于通信
        acpt_soc = accept(echo_soc, (struct sockaddr *)&clnt_addr, &addr_len);
        if (acpt_soc == INVALID_SOCKET)
        {
            printf("[Echo Server] accept error:%d\n", WSAGetLastError());
            break;  // 接受失败时退出循环
        }

        // 接收客户端数据
        result = recv(acpt_soc, recv_buf, ECHO_BUF_SIZE, 0);
        if(result > 0)
        {
            recv_buf[result] = 0;  // 添加字符串结束符
            // 打印接收到的数据和客户端地址
            printf("[Echo Server] receives:\"%s\",from %s\r\n",
                   recv_buf, inet_ntoa(clnt_addr.sin_addr));
            // 将数据原样返回给客户端
            result = send(acpt_soc, recv_buf, result, 0);
        }

        // 关闭客户端套接字（短连接模式）
        closesocket(acpt_soc);
    }

    // 清理资源
    closesocket(echo_soc);
    WSACleanup();
    return 0;
}